package com.hzxgs.tracelogstarter.util;

import com.alibaba.ttl.TransmittableThreadLocal;
import io.netty.util.AttributeKey;
import org.slf4j.MDC;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description 日志追踪工具类
 * @Author wangzehui
 * @Date 2024/8/12 15:49
 */
public class TraceUtils {

    // 追踪id的名称
    public static final String TRACE_ID_KEY = "traceId";

    // 块id的名称
    public static final String SPAN_ID_KEY = "spanId";

    // 日志链路追踪id信息头
    public static final String TRACE_ID_HEADER = "X-traceId-header";

    // 日志链路块id信息头
    public static final String SPAN_ID_HEADER = "X-spanId-header";

    // 过滤器优先级，值越低越优先
    public static final int FILTER_ORDER = -1;

    // 自增序列
    public static int INCREASE_SEQUENCE = 1000;

    // 链路追踪，线程复用会导致一条链路id不同
    public static final AttributeKey<String> TRACE_ID_ATTR_KEY = AttributeKey.valueOf(TraceUtils.TRACE_ID_KEY);

    public static final AttributeKey<String> SPAN_ID_ATTR_KEY = AttributeKey.valueOf(TraceUtils.SPAN_ID_KEY);

    private static final TransmittableThreadLocal<AtomicInteger> spanNumber = new TransmittableThreadLocal<>();

    /**
     * @Description 创建traceId并赋值MDC
     * @Return void
     * @Author wangzehui
     * @Date 2024/8/12 15:58
     */
    public static void addTrace() {
        String traceId = createTraceId();
        MDC.put(TRACE_ID_KEY, traceId);
        MDC.put(SPAN_ID_KEY, "0");
        initSpanNumber();
    }

    /**
     * @Description 赋值MDC
     * @param traceId
     * @param spanId
     * @Return void
     * @Author wangzehui
     * @Date 2024/8/12 16:04
     */
    public static void putTrace(String traceId, String spanId) {
        MDC.put(TRACE_ID_KEY, traceId);
        MDC.put(SPAN_ID_KEY, spanId);
        initSpanNumber();
    }

    /**
     * @Description 获取MDC中的traceId值
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 16:05
     */
    public static String getTraceId() {
        return MDC.get(TRACE_ID_KEY);
    }

    /**
     * @Description 获取MDC中的spanId值
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 16:06
     */
    public static String getSpanId() {
        return MDC.get(SPAN_ID_KEY);
    }

    /**
     * @Description 清除MDC的值
     * @Return void
     * @Author wangzehui
     * @Date 2024/8/12 16:11
     */
    public static void removeTrace() {
        MDC.remove(TRACE_ID_KEY);
        MDC.remove(SPAN_ID_KEY);
        spanNumber.remove();
    }

    /**
     * @Description 创建traceId
     * 产生规则是： 服务器 IP + 产生 ID 时候的时间 + 自增序列 + 当前进程号
     *
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 16:01
     */
    public static String createTraceId() {
        return getIp() + System.currentTimeMillis() + getIncreaseSequence() + getProcessID();
    }

    /**
     * @Description 获取下一个块id
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 16:10
     */
    public static String getNextSpanId() {
        return String.format("%s.%d", getSpanId(), spanNumber.get().incrementAndGet());
    }

    private static void initSpanNumber() {
        spanNumber.set(new AtomicInteger(0));
    }

    /**
     * @Description 获取服务器ip，返回16进制字符串
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 17:04
     */
    private static String getIp() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            byte[] address = localHost.getAddress();
            return String.format("%02x", address[0] & 0xff)
                    + String.format("%02x", address[1] & 0xff)
                    + String.format("%02x", address[2] & 0xff)
                    + String.format("%02x", address[3] & 0xff);
        } catch (UnknownHostException e) {
            return "7f000001";
        }
    }

    /**
     * @Description 获取自增序列号
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 17:17
     */
    private static String getIncreaseSequence() {
        if (INCREASE_SEQUENCE > 9000) {
            INCREASE_SEQUENCE = 1000;
        } else {
            INCREASE_SEQUENCE++;
        }
        return String.valueOf(INCREASE_SEQUENCE);
    }

    /**
     * @Description 获取进程id
     * @Return java.lang.String
     * @Author wangzehui
     * @Date 2024/8/12 17:22
     */
    private static String getProcessID() {
        return String.valueOf(Thread.currentThread().getId());
    }

}
